﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QuoteOfTheDay;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace QuoteService
{
    /// <summary>
    /// Class created for the qoute server. This will thread
    /// the client connection and process it. Code ideas taken from
    /// CSharpRecipes.
    /// </summary>
    class QuoteServer
    {
        private Quote quote;
        private TcpListener listener;
        private int port;
        private IPAddress address;
        private bool listening;
        private object sync = new object();

        public QuoteServer(IPAddress addr, int port)
        {
            address = addr;
            this.port = port;
            quote = new Quote();
        }

        public void Listen()
        {
            try
            {
                lock (sync)
                {
                    listener = new TcpListener(address, port);
                    listener.Start();
                    listening = true;
                }

                do
                {
                    TcpClient client = listener.AcceptTcpClient();

                    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessClient), client);
                }
                while (listening);
            }
            catch (SocketException se)
            {
                Console.WriteLine("Socket Exception: {0}", se.ToString());
            }
            finally
            {
                StopListener();
            }
        }

        public void StopListener()
        {
            if (listening)
            {
                lock (sync)
                {
                    listening = false;
                    listener.Stop();
                }
            }
        }

        private void ProcessClient(object client)
        {
            TcpClient currClient = client as TcpClient;
            try
            {
                StringBuilder data = new StringBuilder();
                byte[] buffer = new byte[1024];
                using (NetworkStream ns = currClient.GetStream())
                {
                    int bytesRead = 0;
                    ns.ReadTimeout = 120000;

                    do
                    {
                        try
                        {
                            bytesRead = ns.Read(buffer, 0, buffer.Length);
                            if (bytesRead > 0)
                            {
                                ASCIIEncoding encode = new ASCIIEncoding();
                                data.Append(encode.GetString(buffer, 0, bytesRead));
                                ns.ReadTimeout = 1500;
                            }
                        }
                        catch (IOException ioe)
                        {
                            Console.WriteLine("Read timeout: {0}", ioe.ToString());
                        }
                    }
                    while (ns.DataAvailable);

                    char[] separator = new char[1];
                    separator[0] = '|';
                    string[] request = data.ToString().Split(separator);
                    string responseMessage = string.Empty;

                    if (request.Length > 0)
                    {
                        switch (request[0])
                        {
                            case "ADD":
                                if (request.Length > 1)
                                {
                                    Quote q = new Quote(request[1]);
                                    quote.AddQuote(q);
                                    responseMessage = quote.CurrentQuote.Message
                                        + "\r\n\r\n" + quote.CurrentQuote.QuotePostedOn.ToShortDateString();
                                }
                                break;
                            case "GET":
                                quote.RefreshQuote();
                                responseMessage = quote.CurrentQuote.Message
                                        + "\r\n\r\n" + quote.CurrentQuote.QuotePostedOn.ToShortDateString();
                                break;
                            case "REMOVE":
                                if (request.Length > 1)
                                {
                                    quote.RemoveQuote(quote.CurrentQuote);
                                    responseMessage = quote.CurrentQuote.Message
                                        + "\r\n\r\n" + quote.CurrentQuote.QuotePostedOn.ToShortDateString();
                                }
                                break;
                            default:
                                break;
                        }
                    }
                    
                    if (responseMessage.Equals(string.Empty))
                        responseMessage = "Invalid Data Received\r\nUnable to serve a quote.";

                    byte[] sendBytes = Encoding.ASCII.GetBytes(responseMessage);
                    ns.Write(sendBytes, 0, sendBytes.Length);
                }
            }
            finally
            {
                if (currClient != null)
                    currClient.Close();
            }
        }
    }
}
